#pragma once

# include <typeinfo>
#include "Name.h"

namespace _FOGGE_
{
	class  FoRTTI
	{
	public:
		FoRTTI (LPCTSTR pcName, const FoRTTI* pkBaseRTTI);

		const _UTIL_::Name& GetName() const {return m_nameName;}
		const FoRTTI* GetBaseRTTI() const {return m_pkBaseRTTI;}

	protected:
		_UTIL_::Name m_nameName;
		const FoRTTI* m_pkBaseRTTI;
	};
}

// insert in root class declaration
#define FoDeclareRootRTTI(classname) \
	public: \
	static const _FOGGE_::FoRTTI m_RTTI; \
	virtual const _FOGGE_::FoRTTI* GetFoRTTI() const {return &m_RTTI;} \
	static bool foIsExactKindOf(const _FOGGE_::FoRTTI* pkRTTI,	const classname* pkObject) \
	{ \
		if (!pkObject) \
		{ \
			return false; \
		} \
		return pkObject->foIsExactKindOf(pkRTTI); \
	} \
	bool foIsExactKindOf(const _FOGGE_::FoRTTI* pkRTTI) const \
	{ \
		return (GetFoRTTI() == pkRTTI); \
	} \
	static bool foIsKindOf(const _FOGGE_::FoRTTI* pkRTTI, const classname* pkObject) \
	{ \
		if (!pkObject) \
		{ \
			return false; \
		} \
		return pkObject->foIsKindOf(pkRTTI); \
	} \
	bool foIsKindOf(const _FOGGE_::FoRTTI* pkRTTI) const \
	{ \
		const _FOGGE_::FoRTTI* pkTmp = GetFoRTTI(); \
		while (pkTmp) \
		{ \
			if (pkTmp == pkRTTI) \
			{ \
				return true; \
			} \
			pkTmp = pkTmp->GetBaseRTTI(); \
		} \
		return false; \
	} \
	static void* foDynamicCast(const _FOGGE_::FoRTTI* pkRTTI,const classname* pkObject) \
	{ \
		if (!pkObject) \
		{ \
			return false; \
		} \
		return pkObject->foDynamicCast(pkRTTI); \
	} \
	void* foDynamicCast(const _FOGGE_::FoRTTI* pkRTTI) const \
	{ \
		if(foIsKindOf(pkRTTI))\
		{\
			return (void*) this;\
		}\
		else\
		{\
			throw std::bad_cast();\
			return 0;\
		}\
	}

// insert in class declaration
#define FoDeclareRTTI \
	public: \
	static const _FOGGE_::FoRTTI m_RTTI; \
	virtual const _FOGGE_::FoRTTI* GetFoRTTI() const {return &m_RTTI;}

// insert in root class source file
#define FoImplementRootRTTI(rootclassname) \
	const _FOGGE_::FoRTTI rootclassname::m_RTTI(__TEXT(#rootclassname), 0)

// insert in class source file
#define FoImplementRTTI(classname, baseclassname) \
	const _FOGGE_::FoRTTI classname::m_RTTI(__TEXT(#classname), &baseclassname::m_RTTI)

// macros for run-time type testing
#define FoIsExactKindOf(classname, pkObject) \
	classname::foIsExactKindOf(&classname::m_RTTI, pkObject)

#define FoIsKindOf(classname, pkObject) \
	classname::foIsKindOf(&classname::m_RTTI, pkObject)

// macro for run-time type casting
#define FoStaticCast(classname, pkObject) \
	((classname*) pkObject)

#define FoDynamicCast(classname, pkObject) \
	((classname*) classname::foDynamicCast(&classname::m_RTTI, pkObject))




namespace _FOGGE_
{
	class foBaseObject 
	{
		FoDeclareRootRTTI(foBaseObject);
	public:

		foBaseObject(void)
		{
		}

		virtual ~foBaseObject(void)
		{
		}
	};

}
